package com.wang.lottery.domain.strategy.service.algorithm.impl;

import com.wang.lottery.domain.strategy.service.algorithm.BaseAlgorithm;
import org.springframework.stereotype.Component;

import java.security.SecureRandom;
import java.util.List;

/**
 * @author wjh
 * @create 2023-11-01 15:00
 * 【推荐】单项随机概率抽奖，抽到一个已经排掉的奖品则未中奖
 *
 * 单项概率：如果A奖品抽空后，B和C保持目前中奖概率，用户抽奖扔有20%中为A，因A库存抽空则结果展示为未中奖。为了运营成本，通常这种情况的使用的比较多
 *
 * 算法描述：单项概率算法不涉及奖品概率重新计算的问题，那么也就是说我们分配好的概率结果是可以固定下来的。
 * 好，这里就有一个可以优化的算法，不需要在轮训匹配O(n)时间复杂度来处理中奖信息，
 * 而是可以根据概率值存放到HashMap或者自定义散列数组进行存放结果，
 * 这样就可以根据概率值直接定义中奖结果，时间复杂度由O(n)降低到O(1)。
 * 这样的设计在一般电商大促并发较高的情况下，达到优化接口响应时间的目的。
 */
@Component("singleRateRandomDrawAlgorithm")
public class SingleRateRandomDrawAlgorithm extends BaseAlgorithm {
    /**
     * 使用随机数抽奖，排除已经抽完的奖品，返回中奖结果
     * @param strategyId      策略id
     * @param excludeAwardIds 排除的奖品id列表
     * @return 中奖的奖品id，没中奖就返回“未中奖”
     */
    @Override
    public String randomDraw(Long strategyId, List<String> excludeAwardIds) {
        String[] rateTuple = super.rateTupleMap.get(strategyId);
        SecureRandom secureRandom = new SecureRandom();
        int randomVal = secureRandom.nextInt(100) + 1;
        String awardId = rateTuple[hashIdx(randomVal)];
        if (excludeAwardIds.contains(awardId)) {
            return null;
        }
        return awardId;
    }
    /**
     * 判断是否做了数据初始化
     *
     * @param strategyId 策略id
     * @return true为已经初始化，false为未初始化
     */
    @Override
    public boolean isExistRateTuple(Long strategyId) {
        return rateTupleMap.containsKey(strategyId);
    }
}
